package num;

import java.io.Serializable;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Random;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.naming.NamingException;

import org.ntu.csn.as.manager.DBManager;

//handle interfaces with web
/**
 *
 * @author hongjun
 */
public class WebManager extends VarManager implements Serializable {

    private static final long serialVersionUID = 1L;
    private int curr_id = 0;
    private int answer;
    private boolean success;
    private int progress = 0;
    protected Random random = new Random();
    protected String Curr_temp;
    protected String qqtype="WholeNumber";
    //Alg Section
    protected Set<String> s = new LinkedHashSet<String>(20);
    protected String algPool = "wxyzbcdefghjkmnpqrstuvwxyz";//don't add a,l,o,i which are confusing..
    protected String algQuestion;//don't add a,l,o,i which are confusing..
    protected Set<String> o = new LinkedHashSet<String>(20);
    String[] AlgSingleFmt = {"\\b[0-9]*[a-zX-Z]\\b"};


    public String getCurr_temp() {
        return Curr_temp;
    }

    public String getQQtype() {
        return qqtype;
    }

    public void setQQtype(String qqtype) {
        this.qqtype = qqtype;
    }

    public void setCurr_temp(String Curr_temp) {
        this.Curr_temp = Curr_temp;
    }

    public WebManager() throws SQLException {
        super();
        qqtype = "All";
    }

    public String getHint() {
        return "" + hint;
    }

    public void setHint(String hint) {
        this.hint = hint;
    }

    public boolean getSuccess() {
        return success;
    }

    public int getProgress() {
        return progress;
    }

    public void setSuccess(boolean success) {
        this.success = success;
    }

    public String getVariable(String var_desc) {
        return tok.getVariable(var_desc);
    }

    public int getMin(String var_desc) { //min:step:max
        return tok.getMin(var_desc);
    }

    public int getStep(String var_desc) { //min:step:max
        return tok.getStep(var_desc);
    }

    public int getMax(String var_desc) { //min:step:max
        return tok.getMax(var_desc);
    }

    public String getTimType(String var_desc) { //min:step:max
        return tok.getTimType(var_desc);
    }

    public String getOrdType(String var_desc) { //min:step:max
        return tok.getOrdType(var_desc);
    }

    public String getFraType(String var_desc) { //min:step:max
        return tok.getFraType(var_desc);
    }

    public boolean hasFraction() {
        for (int i = 0; i < VarList.size(); i++) {
            if (getVariable(VarList.get(i)) != null) {
                if (getFraType(VarList.get(i)).equals("isFra")) {
                    return true;
                }
            }
        }

        return false;
    }

    public int getQuestionId() {
        return curr_id;
    }

    public String getDefaultQuestion() {
        return dft_ques_tpl;
    }

    public String getQuestion1(int oldq) {
        //TODO: request variable values from VarManager
        tpquestion = in_ques_tpl;
        if (oldq == 0 || (ValList.size() != VarList.size())) {
            try {
                getrValList(0);
                getrPhsNamList(0);
            } catch (SQLException ex) {
                hint = "Unable to gerate question. Check the variables expression";
                //Logger.getLogger(WebManager.class.getName()).log(Level.SEVERE, null, ex);
            }
            tpquestion = nam_sub(tpquestion);
        }
        if (oldq == 1) {
            try {
                getrPhsNamList(0);
            } catch (SQLException ex) {
                hint = "Unable to gerate question. Check the variables expression";
                //Logger.getLogger(WebManager.class.getName()).log(Level.SEVERE, null, ex);
            }
            tpquestion = nam_sub(tpquestion);
        }

        tpquestion = var_sub(tim_sub(ord_sub(tpquestion)));

        tpquestion = tpquestion.replace("\n", "<br>");
        tpquestion = tpquestion.replace("\t", "<br>");
        return tpquestion;
    }

    public void setVariable(String var_desc) {
        hint = "no hint";
        if (var_desc.indexOf(":") == -1) {
            setVariable(var_desc + ":2:1:100:isNumber:isNumber:isNumber");
            return;
        } else if (var_desc.indexOf(":") != -1) {
            for (int i = 0; i < VarList.size(); i++) {
                if (getVariable(var_desc).equals(getVariable(VarList.get(i)))) {
                    VarList.remove(i);
                    VarList.add(i, var_desc);
                    return;
                }

            }
            VarList.add(var_desc);
            return;
        }
    }

    public void setRelation(String var_desc) {
        hint = "no hint";

        /*
        if (var_desc.indexOf("=") != -1) {
        return;
        } else if (var_desc.indexOf("=") == -1) {
         * */

        for (int i = 0; i < RelList.size(); i++) {
            if (var_desc.equals(RelList.get(i))) {
                return;
            }
        }
        RelList.add(var_desc);
        return;
        /*
         * }
         * 
         */
    }

    public void setSolution(String var_desc) {
        hint = "no hint";
        /*
        if (var_desc.indexOf("=") != -1) {
        return;
        } else if (var_desc.indexOf("=") == -1) {
         * */

        for (int i = 0; i < SolList.size(); i++) {
            if (var_desc.equals(SolList.get(i))) {
                return;
            }
        }
        SolList.add(var_desc);
        
        //hj create binding relations.
        String tempRel=getSolutionExpr(var_desc);
        if (tempRel.length()>0 && this.qqtype.equals("WholeNumber")){
            RelList.add(tempRel+">0");
            
        }
        return;
        /*
         * }
         * 
         */
    }

    public void setTemplate(String var_desc) {
        hint = "no hint";
        /*
        if (var_desc.indexOf("=") != -1) {
        return;
        } else if (var_desc.indexOf("=") == -1) {
         * */

        for (int i = 0; i < TplList.size(); i++) {
            if (var_desc.equals(TplList.get(i))) {
                return;
            }
        }
        TplList.add(var_desc);
        return;
        /*
         * }
         * 
         * 
         */
    }

    public ArrayList getRelationList() {
        return RelList;
    }

    public ArrayList getVariableList() {
        return VarList;
    }

    public ArrayList getSolutionList() {
        return SolList;
    }

    public ArrayList getTemplateList() {
        return TplList;
    }

    public String getSolutionExpl(String var_desc, int subit) {
        String[] sol = new String[2];
        sol = var_desc.split("var_sep");
        if (var_desc.indexOf("var_sep") == 0) {
            return "";
        }
        if (subit == 1) {
            sol[0] = nam_sub(sol[0]);
            sol[0] = var_sub(sol[0]);//hj 
        }


        return sol[0];
    }

    public String getSolutionExpr(String var_desc) {
        String[] sol = new String[2];
        sol = var_desc.split("var_sep");
        if (sol.length == 1 && var_desc.indexOf("var_sep") > 0) {
            return "";
        } else {
            return sol[1];
        }
    }

    public String getSolutionExprNum(String var_desc) {
        String[] sol = new String[2];
        sol = var_desc.split("var_sep");
        if (sol.length == 1 && var_desc.indexOf("var_sep") > 0) {
            return "";
        } else {
            return var_sub(sol[1]);
        }
    }

    public void setQuestionId(int id) {
        curr_id = id;
    }

    public String getQuestion0() {
        return in_ques_tpl;
    }

    public void setQuestion0(String question0, int... notvariable) throws SQLException {
//        curr_id=0;
        hint = "no hint";
        int int_num;
        in_ques_tpl = question0;
        Pattern pattern2;
        Matcher matcher2;
                  
        if (notvariable.length == 1 && notvariable[0] == 1) //no new variable enter
        {
            return;
        }
        tpquestion = "";
        String var_pat="var_int[0-9][0-9]*"; //search all var_int1 var_int2...
        //String[] varPattern = "var_int|var_double|var_fraction|var_name".split("\\|");
        //int[] varOccur = {0, 0, 0, 0, 0, 0, 0, 0, 0};
        VarList.clear();
        RelList.clear();
        SolList.clear();
        TplList.clear();
        pattern2 =
                    Pattern.compile(var_pat);

            matcher2 =
                    pattern2.matcher(question0);
        while (matcher2.find()) { 
                setVariable(question0.substring(matcher2.start(), matcher2.end()));
            }

        this.setNamQuestion(in_ques_tpl);
        if (qqtype.equals("Algebra")) 
            setAlgManager(in_ques_tpl);     

    }

    
    public String AutoGenVar(String str) {
        //this function generate the question template automatically
        String[] ppt = {"var_int[0-9]{2,100}","var_int[0-9][0-9]*","[0-9][0-9]*\\.[0-9][0-9]*","[0-9][0-9]*", "(three|four|five|six|seven|eight|nine|ten) times","(one|two|three|four|five|six|seven|eight|nine|ten)", "twice", "thrice" };
        String out = str;
        String result=str;
                  Pattern pattern2;
                  Matcher matcher2;
        int j = 1;
        for (int i = 0; i < ppt.length; i++) {
            pattern2 =
                    Pattern.compile(ppt[i]);

            matcher2 =
                    pattern2.matcher(str);

            while (matcher2.find()) {
                //check if any wrong words captured
                if (matcher2.start()>0 && str.charAt(matcher2.start()-1)>='A' && str.charAt(matcher2.start()-1)<='z')
                    continue;
                if (matcher2.end()<str.length() && str.charAt(matcher2.end())>='A' && str.charAt(matcher2.end())<='z')
                    continue;
                out = out.replace(str.substring(matcher2.start(), matcher2.end()), "tmp_tag");
            }
            
                out = out.replaceAll("(tmp_tag){1,}", "tmp_tag"); //avoid 7 77 ->tmp_tag tmp_tagtmp_tag
        }
        result=out;
            pattern2 =
                    Pattern.compile("tmp_tag");

            matcher2 =
                    pattern2.matcher(out);
            j=1;

            while (matcher2.find()) {
                String newvar="var_int"+String.valueOf(j);
                result = result.replaceFirst(out.substring(matcher2.start(), matcher2.end()), newvar);
                setVariable(newvar);
                j++;
            }
        return result;
    }

    public void reset() throws SQLException {
        setQuestion0(getDefaultQuestion(), 0);
        setQuestionId(-1);
    }

    private int occur(String myString, String myPattern) {
        int count = 0;
        for (int i = 0; (i = myString.indexOf(myPattern, i)) >= 0; i++) {
            count += 1;
        }

        return count;
    }

    public String ord_sub(String var_desc) {
        for (int i = 0; i < VarList.size(); i++) {
            if (getVariable(VarList.get(i)) != null) {
                if (getOrdType(VarList.get(i)).equals("isOrder")) {
                    String tosub = NameManager.getOrderForm(ValList.get(i));
                    var_desc = var_desc.replaceAll(getVariable(VarList.get(i)), tosub);
                }
            }
        }
        return var_desc;
    }

    public String tim_sub(String var_desc) {
        for (int i = 0; i < VarList.size(); i++) {
            if (getVariable(VarList.get(i)) != null) {
                if (getTimType(VarList.get(i)).equals("isTimes")) {
                    String tosub = NameManager.getTimesForm(ValList.get(i));
                    var_desc = var_desc.replaceAll(getVariable(VarList.get(i)), tosub);
                }
            }
        }
        return var_desc;
    }

    public String var_sub(String var_desc) {
        String tosub;
         
        for (int i = 0; i < VarList.size(); i++) {
            if (getVariable(VarList.get(i)) != null) {
                if (getFraType(VarList.get(i)).equals("isFra")) {
                    tosub = String.valueOf((float) ValList.get(i) / 100);
                } else {
                    tosub = String.valueOf(ValList.get(i));
                }
                var_desc = var_desc.replaceAll(getVariable(VarList.get(i)), tosub);
            }
        }

        //Alg!!!!!!!
        var_desc=getAlg(var_desc);
        return var_desc;
    }

    public String nam_sub(String var_desc) {
        for (int i = 0; i < PhsNamList.size(); i++) {
            if (PhsNamList.get(i) != null && rPhsNamList.get(i) != null) {
                String tosub = rPhsNamList.get(i);
                var_desc = (new NameManager().replaceAllWords(var_desc, PhsNamList.get(i), tosub));
            }
        }
       
        //hj check any heshe
        for (int i = 0; i < englishHeShe.length; i++) {
            if (var_desc.toLowerCase().contains(" " + englishHeShe[i] + " ")||
                    var_desc.toLowerCase().startsWith(englishHeShe[i] + " ")||
                    var_desc.toLowerCase().endsWith(" " + englishHeShe[i])) {
                int found = 0;
                for (int j = 0; j < rPhsNamList.size() && found == 0; j++) {
                    try {
                        found = DBManager.isHeShe(rPhsNamList.get(j));
                    } catch (SQLException ex) {
                        return var_desc;
                    } catch (NamingException ex) {
                        return var_desc;
                    }
                }
                if (found == 1 || found == 2) {
                    if (found == 1 && (i + 1) % 2 == 1) {
                        //new name is she, question has he, he ->she
                        for (int k = i; k < englishHeShe.length; k = k + 2) {
                            var_desc = (new NameManager().replaceAllWords(var_desc, englishHeShe[k], englishHeShe[k + 1]));
                        }
                    }
                    if (found == 2 && (i + 1) % 2 == 0) {
                        //she->he
                        for (int k = i; k < englishHeShe.length; k = k + 2) {
                            var_desc = (new NameManager().replaceAllWords(var_desc, englishHeShe[k], englishHeShe[k - 1]));
                        }
                    }
                }
                if (found != 0) {
                    return var_desc;
                }
            }
        }
        
        return var_desc;
    }
    
    /********************************************************************
     * @param inq
     * @throws SQLException 
     */
    public void setNamQuestion(String inq) throws SQLException {
        //reset related arraylist
        PhsNamList.clear();
        TypNumList.clear();
        TypNamList.clear();


        String[] var_array = inq.split("\\W+");
        ArrayList<Integer> a = new ArrayList<Integer>();

        //check each item exists in database or not
        for (int i = 0; i < var_array.length; i++) {
            String temp = var_array[i];
            if (temp.length() < 3) {
                continue;
            }
            temp = (new NameManager().dbNames(temp));
            if (!PhsNamList.contains(temp) && !PhsNamList.contains(temp)) {
                a = (DBManager.isPhraseExist(temp));
                if (a.size() > 0) {
                    //hj: important arraylist adds only reference, so need to make sure new array initialized 
                    Integer[] typ_array = new Integer[4];
                    a.toArray(typ_array);
                    //hj TODO: the type array might be all 0s
                    PhsNamList.add(temp);
                    TypNumList.add(typ_array);
                }
            }
        }


        for (int i = 0; i < TypNumList.size(); i++) {
            Integer[] typnum_array = new Integer[4];
            String[] typnam_array = new String[4];
            typnum_array = TypNumList.get(i);
            for (int j = 0; j < typnum_array.length && typnum_array[j] != 0; j++) {
                typnam_array[j] = DBManager.TypNumNam(typnum_array[j]);
            }
            TypNamList.add(typnam_array);
        }
        this.in_ques_tpl = inq;
    }

    public ArrayList<String> getPhsNamList() {
        return PhsNamList;
    }

    public void setPhsNamList(ArrayList<String> PhsNamList) {
        this.PhsNamList = PhsNamList;
    }

    public ArrayList<String[]> getTypNamList() {
        return TypNamList;
    }

    public ArrayList<Integer[]> getTypNumList() {
        return TypNumList;
    }

    public void setTypNumList(ArrayList<Integer[]> TypNumList) throws SQLException {
        this.TypNumList = TypNumList;

    }

    //hj format the output to display on 
    public String MeDi(String str) {

        str = str.replaceAll("sqrt", "SQRT");
        str = str.replaceAll("pow", "POW");
        if (str.contains("POW")) {
            str = DisPow(str);
        }
        str = DisFra(str);

        return str;
    }

    public String DisPow(String str) {
        String tmp = "";
        Pattern pattern =
                Pattern.compile("POW\\([a-z0-9]*,[a-z0-9]*\\)");

        Matcher matcher =
                pattern.matcher(str);

        boolean found = false;
        int tmpindex = 0;
        while (matcher.find()) {
            String arr[] = matcher.group().split("[(,)]");
            String query = "<i>" + arr[1] + "</i><sup>" + arr[2] + "</sup>";
            tmp = tmp + str.substring(tmpindex, matcher.start()) + query;
            tmpindex = matcher.end();
            found = true;

        }
        tmp = tmp + str.substring(tmpindex);
        return tmp;
    }

    public String DisFra(String str) {
        String query = str;
        if (true) {
            return query;
        }
        String arr[] = str.split("/");

        if (arr.length == 2) {
            query = "<sup>" + arr[0] + "</sup>&frasl;<sub>" + arr[1] + "</sub>";
        }
        return query;
    }
    
        /*
     * xy->mn
     * xyz->mnk
     * 
     */
    public  String AlgFormater(String str) { 
        if (!isAlg()) return str;
        String tmp ="";
        //handling the *
        //handling xy... caese
        String AlgMorePat="";
        for (int i = 0; i < s.size(); i++) {
            AlgMorePat=AlgMorePat+s.toArray()[i].toString();
        }
        Pattern pattern2 =
               Pattern.compile("\\b[0-9]*["+AlgMorePat+"]{2,}\\b");  

        Matcher matcher2 =
                pattern2.matcher(str);
        int k = 0;
         String newtmp="";
        while (matcher2.find()) {
            if(str.substring(matcher2.start(), matcher2.end()).replaceFirst("[0-9]*", "").length()<2) continue;
            tmp=(str.substring(matcher2.start(), matcher2.end()));
           
            for (int i=0;i<tmp.length();i++){
                if (getIndex(s,String.valueOf(tmp.charAt(i)))==-1)
                    newtmp=newtmp+String.valueOf(tmp.charAt(i));
                else
                newtmp=newtmp+o.toArray()[getIndex(s,String.valueOf(tmp.charAt(i)))].toString();
            }
            str=str.replace(tmp,newtmp);
        }
        return str;
    }
    
    public void setAlgManager(String str){
        if (!isAlg()) return;
        if (str.isEmpty()) return;
        str=str.replaceAll("var_int", "");
        str=str.replaceAll("(a)", "(A)");
        str=str.replaceAll("(b)", "(B)");
        str=str.replaceAll("(c)", "(C)");
        str=str.replaceAll("(d)", "(D)");
        this.algQuestion=str;
        s.clear();
        o.clear();
        Pattern pattern2;
        Matcher matcher2;
        for (int i = 0; i < AlgSingleFmt.length; i++) {
            pattern2 =
                    Pattern.compile(AlgSingleFmt[i]);
            matcher2 =
                    pattern2.matcher(str);
            while (matcher2.find()) {
                s.add(str.substring(matcher2.end()-1,matcher2.end()));
            }
        }
        int rand= Math.abs(random.nextInt() % (26-s.size()));
        for (int i = 0; i < s.size(); i++) {
            o.add(String.valueOf(algPool.charAt(rand+i)));
        }
    }
    
    public String getAlg(String str){
        if (!isAlg()) return str;
        if (s.isEmpty()||o.isEmpty()) return str;
        str=AlgFormater(" "+str+" ");
        String out="";
        Pattern pattern2;
        Matcher matcher2;
        for (int i = 0; i < AlgSingleFmt.length; i++) {
            pattern2 =
                    Pattern.compile(AlgSingleFmt[i]);

            matcher2 =
                    pattern2.matcher(str);
            int pend=0;            
            String[] tPar=new String[20];
            int j = 0;   
            
            while (matcher2.find()) {
                if (o.toArray()[0].toString().equals("w")){
                    j=0;
                }
                String tmp=str.substring(matcher2.end()-1,matcher2.end());
                int index=getIndex(s,tmp);
                String tosub=tmp;
                if (index>=0 && o.size()>index) 
                    tosub=String.valueOf(o.toArray()[index]);
                tPar[j]=str.substring(pend, matcher2.end()-1)+tosub;
                out=out+tPar[j];
                pend=matcher2.end(); 
                j++;
            }
            tPar[j]=str.substring(pend);
            out=out+tPar[j];
        }
        return out.length()>0?out:str;
    }
    
  public int getIndex(Set<String> ss, String str) {
     int result = -1;
     if (str.length()!=1) return result;
     
     Iterator itr = ss.iterator(); 
     while(itr.hasNext()) {
         
    result++;
    if (itr.next().equals(str)) return result; 

} 
     return -1;
   }
  public boolean isAlg(){
      if (this.getQQtype().equals("Algebra"))
          return true;
      return false;
  }
  

    //hj: testing function
    public static void main(String args[]) throws SQLException {

        //String str="(69-68)p+(11-52)q+(66-32)r";
        String str;
        //str="sqrt(pow(6,2)+pow(8,2))p";
        //str="((10-4)/10)x";
        str="p plus 3r t what plan is 2r plus 3p. 4m";
        //str = "Joyce has $60 23/25 60 one two three good 2 men 1 woman . If Carol gives Joyce $20.73, the amount of five times Joyce has will be thrice that of Carol's. How much money has each of them at first.";
        //Pattern pattern2 = Pattern.compile("[0-9][0-9]*\\.[0-9][0-9]*"); 
        String[] ppt = {"\\b[1-9]*[a-zA-Z]\\b"};
        String out=new String();
        String result=str;
        Pattern pattern2;
        Matcher matcher2;
        int j = 0;
        for (int i = 0; i < ppt.length; i++) {
            pattern2 =
                    Pattern.compile(ppt[i]);

            matcher2 =
                    pattern2.matcher(str);

            int pend=0;
            
            String[] tPar=new String[10];
            while (matcher2.find()) {
                tPar[j]=str.substring(pend, matcher2.end()-1)+"var_tab ";
                out=out+tPar[j];
                pend=matcher2.end();
                //out = out.replaceFirst(str.substring(matcher2.start()+1, matcher2.end()-1), "var_tag");
                
               System.out.println(out);
                j++;
            }
            tPar[j]=str.substring(pend);
            out=out+tPar[j];
        }
 
 System.out.println(out);
    }
}
